package _effx
{
   import _effx.visual.PerlinField;
   
   import com.greensock.easing.Quint;
   
   import flash.display.BitmapData;
   import flash.display.BitmapDataChannel;
   import flash.display.Sprite;
   import flash.events.Event;
   import flash.filters.BlurFilter;
   import flash.filters.DisplacementMapFilter;
   import flash.filters.DisplacementMapFilterMode;
   import flash.geom.Point;
   import flash.geom.Rectangle;
   import flash.utils.getDefinitionByName;
   
   import org.flintparticles.common.actions.Age;
   import org.flintparticles.common.actions.Fade;
   import org.flintparticles.common.counters.Random;
   import org.flintparticles.common.counters.ZeroCounter;
   import org.flintparticles.common.initializers.AlphaInit;
   import org.flintparticles.common.initializers.ImageClass;
   import org.flintparticles.common.initializers.Lifetime;
   import org.flintparticles.common.initializers.ScaleImageInit;
   import org.flintparticles.twoD.actions.LinearDrag;
   import org.flintparticles.twoD.actions.Move;
   import org.flintparticles.twoD.actions.RandomDrift;
   import org.flintparticles.twoD.emitters.Emitter2D;
   import org.flintparticles.twoD.initializers.Position;
   import org.flintparticles.twoD.initializers.Velocity;
   import org.flintparticles.twoD.renderers.BitmapRenderer;
   import org.flintparticles.twoD.zones.LineZone;
   import org.flintparticles.twoD.zones.PointZone;
   
   /**
    * Smoking Effect
    * @author boy, cjboy1984@gmail.com
    * todo:
    * stage edition
    */
   public class CigaretteSmoke_1 extends Sprite
   {
      private const CANVAS_W:Number = 500;
      private const CANVAS_H:Number = 500;
      
      // particle
      private var pCanvas:BitmapRenderer;
      private var emSmoke:Emitter2D;
      
      // filter
      private var blurFilter:BlurFilter;
      private var dspFilter:DisplacementMapFilter;
      
      // perlin
      private var perlinNoz:PerlinField; // <-- very important
      public function get nozBmpd():BitmapData { return perlinNoz.bitmapData; }
      
      public function CigaretteSmoke_1()
      {
         // basic
         mouseChildren = false;
         mouseEnabled = false;
         
         addEventListener(Event.ADDED_TO_STAGE, onAdd);
         addEventListener(Event.REMOVED_FROM_STAGE, onRemove);
      }
      
      // ________________________________________________
      //                                            basic
      
      public function start():void
      {
         emSmoke.counter = new Random(0, 30);
         emSmoke.start();
         
         if (!hasEventListener(Event.ENTER_FRAME))
         {
            addEventListener(Event.ENTER_FRAME, updateAll);
         }
      }
      
      public function pause():void
      {
         emSmoke.counter = new ZeroCounter();
      }
      
      public function stop():void
      {
         emSmoke.pause();
         
         removeEventListener(Event.ENTER_FRAME, updateAll);
      }
      
      public function stopAndKill():void
      {
         emSmoke.stop();
         
         removeEventListener(Event.ENTER_FRAME, updateAll);
         
         // perlin
         perlinNoz.dispose();
      }
      
      // ________________________________________________
      //                                            utils
      
      public function applyFilter():void
      {
         pCanvas.addFilter(blurFilter, true);
         pCanvas.addFilter(dspFilter, true);
      }
      
      public function removeFilter():void
      {
         pCanvas.removeFilter(blurFilter);
         pCanvas.removeFilter(dspFilter);
      }
      
      // ################### protected ##################
      
      // #################### private ###################
      
      
      private function onAdd(e:Event):void
      {
         init();
         initSmoke();
         initFilter();
      }
      
      private function onRemove(e:Event):void
      {
         emSmoke.stop();
         
         emSmoke = null;
         
         pCanvas = null;
         
         perlinNoz.dispose();
      }
      
      // ________________________________________________
      //                                             init
      
      private function init():void
      {
         pCanvas = new BitmapRenderer(new Rectangle(0, 0, CANVAS_W, CANVAS_H), false);
         addChild(pCanvas);
      }
      
      // ________________________________________________
      //                                         particle
      
      private function initSmoke():void
      {
         var viewCls:Class = getDefinitionByName('Smoke') as Class;
         
         emSmoke = new Emitter2D();
         emSmoke.x = 246;
         emSmoke.y = 327;
         
         emSmoke.addInitializer(new Lifetime(1, 3));
         emSmoke.addInitializer(new Velocity(new LineZone(new Point(0,-100), new Point(0,-150))));
         emSmoke.addInitializer(new Position(new PointZone(new Point(0, -6))));
         emSmoke.addInitializer(new ImageClass(viewCls));
         emSmoke.addInitializer(new ScaleImageInit(0.5, 1.0));
         emSmoke.addInitializer(new AlphaInit(0.2, 1));
         
         emSmoke.addAction(new Age(Quint.easeIn));
         emSmoke.addAction(new Move());
         emSmoke.addAction(new LinearDrag(-0.11));
         emSmoke.addAction(new Fade(1, 0));
         emSmoke.addAction(new RandomDrift(50, 100));
         
         pCanvas.addEmitter(emSmoke);
      }
      
      // ________________________________________________
      //                                           filter
      
      private function initFilter():void
      {
         // double size of width and height
         perlinNoz = new PerlinField(pCanvas.width, pCanvas.height);
         perlinNoz.channels = 1|2|4; // R+G
         perlinNoz.numOctaves = 1;
         
         // disable y-direction
         perlinNoz.velocityPool[0].x = -0.5;
         perlinNoz.velocityPool[0].y = +1.0;
         
         // displacement filter
         var PERLIN_STRENGTH:Number = 1;
         dspFilter = new DisplacementMapFilter();
         dspFilter.mapPoint = new Point();
         dspFilter.componentX = BitmapDataChannel.RED;
         dspFilter.componentY = BitmapDataChannel.GREEN;
         dspFilter.mode = DisplacementMapFilterMode.COLOR;
         dspFilter.mapBitmap = perlinNoz.bitmapData;
         dspFilter.scaleX = 55;
         dspFilter.scaleY = 110;
         
         blurFilter = new BlurFilter(10, 50);
      }
      
      // ________________________________________________
      //                                      enter frame
      
      private function updateAll(e:Event):void
      {
         perlinNoz.update();
      }
      
      // --------------------- LINE ---------------------
      
   }
   
}
